-- 按键堆叠
function XS_KeyStack()
    local entities_only = {} -- 不可堆叠物品
    local entities_full = {} -- 堆叠数量已满物品
    local entities = {}      -- 堆叠数量未满物品

    -- 世界物品搜索并分类
    local world_entities = XS:GetAroundEntities(TUNING.XS_AUTO_STACK_RADIUS * 4, nil, { "isinventoryitem" },
        XS_DefaultExcludeTags)
    for _, inst in pairs(world_entities) do
        local inst_c = inst.components
        if inst:IsValid() and inst_c.inventoryitem and not (inst_c.inventoryitem.owner or inst_c.health or inst_c.mine
                or inst_c.trap or (inst_c.bait and inst_c.bait.trap)) then
            if inst_c.stackable then
                -- 可堆叠物品
                if not inst_c.stackable:IsFull() then
                    -- 物品堆叠数量未满
                    if not entities[inst.prefab] then
                        entities[inst.prefab] = {}
                    end
                    table.insert(entities[inst.prefab], inst)
                else
                    -- 物品堆叠数量已满
                    table.insert(entities_full, inst)
                end
            else
                -- 不可堆叠物品
                table.insert(entities_only, inst)
            end
        end
    end

    -- 处理堆叠数量未满物品
    local new_entities = {}
    for _, ent_items in pairs(entities) do
        --print("可堆叠物品: " .. ent_items[1].name .. "  物品个数: " .. #ent_items)
        local prefab_maxsize = ent_items[1].components.stackable.maxsize
        local spread_inst = table.remove(ent_items) -- 被合并物品
        local spread_inst_position = XS:GetPosition(spread_inst)
        -- 所有物品合并完毕结束
        while #ent_items > 0 do
            for index, inst in pairs(ent_items) do
                local res = XS:InstMerge(inst, spread_inst)
                -- 被合并物品已全部合并
                if not res.inst2 then
                    SpawnPrefab("small_puff").Transform:SetPosition(spread_inst_position:Get())
                    spread_inst = table.remove(ent_items)
                    spread_inst_position = XS:GetPosition(spread_inst)
                    break
                end
                -- 当前物品已满
                if res.inst1.components.stackable.stacksize >= prefab_maxsize then
                    table.insert(new_entities, table.remove(ent_items, index))
                    break
                end
            end
        end
        -- 所有物品合并完后被合并物品还有剩余
        if spread_inst and spread_inst:IsValid() then
            table.insert(new_entities, spread_inst)
        end
    end

    -- 物品牵引
    local position = XS:GetPosition()
    -- 按键堆叠物品
    if HasTableValue({ 1, 2, 4 }, TUNING.XS_AUTO_STACK_GATHER_LEVEL) then
        for _, inst in pairs(new_entities) do
            if TUNING.XS_AUTO_STACK_GATHER_WAY then
                XS:DropScatter(nil, inst)
            else
                inst.Transform:SetPosition(position:Get())
            end
        end
    end
    -- 可堆叠物品
    if HasTableValue({ 2, 4 }, TUNING.XS_AUTO_STACK_GATHER_LEVEL) then
        for _, inst in pairs(entities_full) do
            if TUNING.XS_AUTO_STACK_GATHER_WAY then
                XS:DropScatter(nil, inst)
            else
                inst.Transform:SetPosition(position:Get())
            end
        end
    end
    -- 不可堆叠物品
    if HasTableValue({ 3, 4 }, TUNING.XS_AUTO_STACK_GATHER_LEVEL) then
        for _, inst in pairs(entities_only) do
            if TUNING.XS_AUTO_STACK_GATHER_WAY then
                XS:DropScatter(nil, inst)
            else
                inst.Transform:SetPosition(position:Get())
            end
        end
    end
end